using System;
using ValidationFramework.Reflection;
using ValidationFramework.Configuration.Reflection;

namespace ValidationFramework.Specifications
{
#if (!SILVERLIGHT)
	[Serializable]
#endif
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.Field, AllowMultiple = true, Inherited = true)]
	public class IsRequiredAttribute : RuleAttribute
	{
		// --- Properties

		/// <summary>
		/// Gets or sets the initial and invalid value.
		/// </summary>
		/// <seealso cref="RequiredRule{T}.InitialValue"/>
		public object InitialValue { get; set; }


		// --- Methods
		public override ISpecification CreateSpecification(ICachedReflectionInfo descriptor)
		{
            // Guard
			var typeParam = Type.GetTypeFromHandle(descriptor.MemberTypeHandle);
			if (InitialValue != null && !InitialValue.GetType().IsAssignableFrom(typeParam))
			{
				throw new ArgumentOutOfRangeException(
					string.Format(
					"InitialValue of type '{0}' cannot be an initialValue for a member of type '{1}'", 
					InitialValue.GetType().Name, 
					Type.GetTypeFromHandle(descriptor.MemberTypeHandle).Name));
			}

			var genericType = typeof(IsRequiredSpec<>);
			

			if (InitialValue == null)
                return (ISpecification)GenericTypeFactory.CreateInstance(genericType, typeParam);
			else
                return (ISpecification)GenericTypeFactory.CreateInstance(genericType, typeParam, InitialValue);
		}
	}
}
